#pragma once

#include <iostream>
#include <functional>
#include <atomic>
#include <mutex>
#include <thread>
#include <set>
#include <chrono>
#include <string>
#include <memory>
#include <string>

#include "./helpper.hpp"

struct TimerTask
{
	using task_t = std::function<void()>;
	task_t task;
	uint64_t delayed;
	uint64_t interval;
	std::string task_id;

	TimerTask(task_t &&task, uint64_t delayed, uint64_t interval, const std::string &id)
		: task(task), delayed(delayed), interval(interval), task_id(id)
	{
	}

	bool operator<(const TimerTask &o) const
	{
		return delayed < o.delayed;
	}
};

class Timer
{
public:
	using Ptr = std::shared_ptr<Timer>;
	Timer() : is_running(true), _timer(&Timer::run, this)
	{
	}

	void push(TimerTask::task_t &&task, uint64_t delayed, uint64_t interval, const std::string &id)
	{
		// DLOG("获取锁");
		std::unique_lock<std::mutex> ul(_mtx);
		// DLOG("获取到锁");
		s.emplace(std::forward<TimerTask::task_t>(task), now() + delayed, interval, id);
	}

	uint64_t now()
	{
		auto now = std::chrono::high_resolution_clock::now();
		auto timestamp = std::chrono::duration_cast<std::chrono::seconds>(
							 now.time_since_epoch())
							 .count();

		return timestamp;
	}

	void run()
	{
		while (is_running.load(std::memory_order_relaxed))
		{
			// DLOG("获取运行锁");

		std::unique_lock<std::mutex> ul(_mtx);
			// DLOG("获取到运行锁");
			if (s.empty())
			{
				std::this_thread::sleep_for(std::chrono::milliseconds(1));
			}
			else
			{
				auto begin = s.begin();
				while (begin != s.end())
				{

					auto cur = begin++;
					if (cur->delayed <= now())
					{
						ul.unlock();
						try
						{
							cur->task();
						}
						catch (...)
						{
							ELOG("定时器任务执行失败");
						}
						ul.lock();
						if (cur->interval != 0)
						{
							TimerTask::task_t t = cur->task;
							uint64_t delayed = cur->delayed + cur->interval;
							uint64_t interval = cur->interval;
							std::string id = cur->task_id;
							TimerTask tmp(std::move(t), delayed, interval, id);
							// push(std::move(t), cur->interval, cur->interval, cur->task_id);
							s.insert(tmp);
							// ELOG("插入循环定时器，定时器容器大小：%ld", s.size());
						}
						s.erase(cur);
					}
				}
			}
		}
	}

	void remove(const std::string &id)
	{
		DLOG("获取删除任务锁");
		std::unique_lock<std::mutex> ul(_mtx);
		DLOG("获到任务锁");
		auto it = s.begin();
		while (it != s.end())
		{
			if (it->task_id == id)
			{
				s.erase(it);
				break;
			}

			++it;
		}
		DLOG("删除任务完成");
	}

	void stop()
	{
		is_running.store(false);
	}

	~Timer()
	{
		stop();
		_timer.join();
	}

private:
	std::multiset<TimerTask> s;
	std::mutex _mtx;
	std::thread _timer;
	std::atomic<bool> is_running;
};